package com.campus.help.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.campus.help.entity.Student;
import com.campus.help.mapper.StudentMapper;
import com.campus.help.service.AuthService;
import com.campus.help.utils.JwtUtils;
import com.campus.help.utils.RedisUtils;
import com.campus.help.utils.WechatUtils;
import com.campus.help.utils.WechatUtils.WechatSessionInfo;
import com.campus.help.utils.WechatUtils.WechatUserInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * 授权登录服务实现类
 *
 * @author campus-help
 * @since 2025-09-18
 */
@Slf4j
@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private WechatUtils wechatUtils;

    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private RedisUtils redisUtils;

    private static final String REDIS_TOKEN_PREFIX = "student:token:";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LoginResult wechatLogin(String code) {
        try {
            // 1. 通过code获取微信session信息
            WechatSessionInfo sessionInfo = wechatUtils.code2Session(code);

            // 2. 根据openid查询学生信息
            Student student = studentMapper.selectOne(
                    new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<Student>()
                            .eq("openid", sessionInfo.getOpenid())
                            .eq("deleted", 0)
            );

            boolean isNewUser = false;

            // 3. 如果学生不存在，创建新学生
            if (student == null) {
                student = new Student();
                student.setOpenid(sessionInfo.getOpenid());
                student.setUnionid(sessionInfo.getUnionid());
                student.setStatus("ACTIVE"); // 正常状态
                student.setCreditScore(100); // 初始信用分
                student.setVerifyStatus(0); // 未认证
                student.setLastLoginTime(LocalDateTime.now());
                student.setDeleted(0); // 未删除
                studentMapper.insert(student);
                isNewUser = true;
                log.info("创建新学生用户: openid={}, studentId={}", sessionInfo.getOpenid(), student.getId());
            } else {
                // 4. 更新最后登录时间
                student.setLastLoginTime(LocalDateTime.now());
                studentMapper.updateById(student);
                log.info("学生用户登录: openid={}, studentId={}", sessionInfo.getOpenid(), student.getId());
            }

            // 5. 生成JWT token
            String token = jwtUtils.generateToken(student.getId(), student.getOpenid());

            // 6. 将token存储到Redis中
            redisUtils.set(REDIS_TOKEN_PREFIX + student.getId(), token);

            return new LoginResult(token, student, isNewUser, sessionInfo.getSessionKey());
        } catch (Exception e) {
            log.error("微信登录失败", e);
            throw new RuntimeException("登录失败", e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Student updateUserInfoSimple(Long studentId, String nickname, String avatarUrl,
                                      Long schoolId, String phone, String qq, String wechat, String email) {
        try {
            log.info("开始简化更新用户信息: studentId={}, nickname={}, avatarUrl={}",  studentId, nickname, avatarUrl);

            // 1. 获取学生信息
            Student student = studentMapper.selectById(studentId);
            if (student == null) {
                throw new RuntimeException("学生不存在");
            }
            log.info("获取学生信息成功: 原nickname={}, 原avatarUrl={}", student.getNickname(), student.getAvatarUrl());

            // 2. 更新用户信息（只更新非空字段）
            if (nickname != null && !nickname.trim().isEmpty()) {
                student.setNickname(nickname.trim());
            }
            if (avatarUrl != null && !avatarUrl.trim().isEmpty()) {
                student.setAvatarUrl(avatarUrl.trim());
            }
            
            // 更新其他字段
            if (schoolId != null) {
                student.setSchoolId(schoolId);
            }
            if (phone != null && !phone.trim().isEmpty()) {
                student.setPhone(phone.trim());
            }
            if (qq != null && !qq.trim().isEmpty()) {
                student.setQq(qq.trim());
            }
            if (wechat != null && !wechat.trim().isEmpty()) {
                student.setWechat(wechat.trim());
            }
            if (email != null && !email.trim().isEmpty()) {
                student.setEmail(email.trim());
            }

            int updateResult = studentMapper.updateById(student);
            log.info("数据库更新结果: updateResult={}", updateResult);

            // 3. 重新查询确保数据已更新
            Student updatedStudent = studentMapper.selectById(studentId);
            log.info("更新后学生信息: nickname={}, avatarUrl={}, schoolId={}, phone={}",
                    updatedStudent.getNickname(), updatedStudent.getAvatarUrl(),
                    updatedStudent.getSchoolId(), updatedStudent.getPhone());

            return updatedStudent;
        } catch (Exception e) {
            log.error("简化更新用户信息失败", e);
            throw new RuntimeException("更新用户信息失败", e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Student updateUserSchool(Long studentId, Long schoolId) {
        try {
            log.info("开始更新用户学校: studentId={}, schoolId={}", studentId, schoolId);

            // 1. 验证学生是否存在
            Student student = studentMapper.selectById(studentId);
            if (student == null) {
                throw new RuntimeException("学生不存在");
            }

            // 2. 验证是否已经设置过学校（可选的业务逻辑）
            if (student.getSchoolId() != null) {
                log.warn("学生已有学校ID: studentId={}, 原schoolId={}, 新schoolId={}", 
                        studentId, student.getSchoolId(), schoolId);
            }

            // 3. 更新学校ID
            student.setSchoolId(schoolId);
            student.setUpdateTime(LocalDateTime.now());
            
            int updateResult = studentMapper.updateById(student);
            log.info("数据库更新结果: updateResult={}", updateResult);

            if (updateResult == 0) {
                throw new RuntimeException("更新学校失败");
            }

            // 4. 重新查询确保数据已更新
            Student updatedStudent = studentMapper.selectById(studentId);
            log.info("更新后学生信息: schoolId={}", updatedStudent.getSchoolId());

            return updatedStudent;
        } catch (Exception e) {
            log.error("更新用户学校失败: studentId={}, schoolId={}", studentId, schoolId, e);
            throw new RuntimeException("更新学校失败: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Student updateUserInfo(Long studentId, String encryptedData, String sessionKey, String iv, 
                                Long schoolId, String phone, String qq, String wechat, String email) {
        try {
            log.info("开始更新用户信息: studentId={}, encryptedData长度={}, sessionKey长度={}, iv长度={}",
                    studentId, encryptedData != null ? encryptedData.length() : 0, 
                    sessionKey != null ? sessionKey.length() : 0, 
                    iv != null ? iv.length() : 0);

            // 1. 解密用户信息
            WechatUserInfo userInfo = null;
            try {
                userInfo = wechatUtils.decryptUserInfo(encryptedData, sessionKey, iv);
                log.info("解密用户信息成功: nickname={}, avatarUrl={}, gender={}",
                        userInfo.getNickname(), userInfo.getAvatarUrl(), userInfo.getGender());
            } catch (Exception decryptException) {
                log.error("解密用户信息失败，可能是由于微信政策调整或数据格式问题", decryptException);
                // 如果解密失败，可能是因为微信政策调整，建议用户使用新的头像昵称填写功能
                throw new RuntimeException("获取用户信息失败，请使用头像昵称填写功能更新个人信息");
            }

            // 2. 获取学生信息
            Student student = studentMapper.selectById(studentId);
            if (student == null) {
                throw new RuntimeException("学生不存在");
            }
            log.info("获取学生信息成功: 原nickname={}, 原avatarUrl={}", student.getNickname(), student.getAvatarUrl());

            // 3. 更新学生信息
            if (userInfo.getNickname() != null && !userInfo.getNickname().trim().isEmpty()) {
                student.setNickname(userInfo.getNickname().trim());
            }
            if (userInfo.getAvatarUrl() != null && !userInfo.getAvatarUrl().trim().isEmpty()) {
                student.setAvatarUrl(userInfo.getAvatarUrl().trim());
            }
            if (userInfo.getGender() != null) {
                student.setGender(userInfo.getGender());
            }
            
            // 更新其他字段
            if (schoolId != null) {
                student.setSchoolId(schoolId);
            }
            if (phone != null && !phone.trim().isEmpty()) {
                student.setPhone(phone.trim());
            }
            if (qq != null && !qq.trim().isEmpty()) {
                student.setQq(qq.trim());
            }
            if (wechat != null && !wechat.trim().isEmpty()) {
                student.setWechat(wechat.trim());
            }
            if (email != null && !email.trim().isEmpty()) {
                student.setEmail(email.trim());
            }

            int updateResult = studentMapper.updateById(student);
            log.info("数据库更新结果: updateResult={}", updateResult);

            // 4. 重新查询确保数据已更新
            Student updatedStudent = studentMapper.selectById(studentId);
            log.info("更新后学生信息: nickname={}, avatarUrl={}, gender={}, schoolId={}, phone={}",
                    updatedStudent.getNickname(), updatedStudent.getAvatarUrl(), updatedStudent.getGender(),
                    updatedStudent.getSchoolId(), updatedStudent.getPhone());

            return updatedStudent;
        } catch (Exception e) {
            log.error("更新用户信息失败", e);
            throw new RuntimeException("更新用户信息失败: " + e.getMessage(), e);
        }
    }

    @Override
    public Student getStudentByOpenid(String openid) {
        return studentMapper.selectOne(
                new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<Student>()
                        .eq("openid", openid)
                        .eq("deleted", 0)
        );
    }

    @Override
    public String generateToken(Student student) {
        return jwtUtils.generateToken(student.getId(), student.getOpenid());
    }

    @Override
    public Student validateToken(String token) {
        try {
            log.debug("开始验证token: {}", token);

            // 1. 验证JWT token
            JwtUtils.TokenInfo tokenInfo = jwtUtils.validateToken(token);
            log.debug("JWT token验证成功, studentId: {}, openid: {}", tokenInfo.getStudentId(), tokenInfo.getOpenid());

            // 2. 从Redis中验证token是否有效
            String redisKey = REDIS_TOKEN_PREFIX + tokenInfo.getStudentId();
            log.debug("从Redis获取token, key: {}", redisKey);

            String redisToken = redisUtils.get(redisKey, String.class);
            if (redisToken == null) {
                log.warn("Redis中未找到token, key: {}", redisKey);
                throw new RuntimeException("Token已失效");
            }

            if (!redisToken.equals(token)) {
                log.warn("Redis中的token与请求token不匹配, redisToken: {}, requestToken: {}", redisToken, token);
                throw new RuntimeException("Token已失效");
            }

            log.debug("Redis token验证成功");

            // 3. 获取学生信息
            Student student = studentMapper.selectById(tokenInfo.getStudentId());
            if (student == null) {
                log.warn("学生不存在, studentId: {}", tokenInfo.getStudentId());
                throw new RuntimeException("学生不存在");
            }

            if (student.getDeleted() == 1) {
                log.warn("学生已被删除, studentId: {}", tokenInfo.getStudentId());
                throw new RuntimeException("学生不存在");
            }

            log.debug("Token验证成功, 学生信息: {}", student.getNickname());
            return student;
        } catch (Exception e) {
            log.error("Token验证失败, token: {}, 错误信息: {}", token, e.getMessage(), e);
            throw new RuntimeException("Token验证失败: " + e.getMessage(), e);
        }
    }

    @Override
    public Long getTotalUsersCount() {
        try {
            // 查询student表中未删除的用户总数
            Long totalCount = studentMapper.selectCount(new LambdaQueryWrapper<Student>().eq(Student::getDeleted, 0));

            log.info("获取用户总数: {}", totalCount);
            return totalCount;
        } catch (Exception e) {
            log.error("获取用户总数失败", e);
            throw new RuntimeException("获取用户总数失败: " + e.getMessage(), e);
        }
    }
}
